#ifndef __UTILS_H__
#define __UTILS_H__

#include <cstdint>
#include <cstdlib>
#include <stdint.h>
#include <stdio.h>
#include "cassert"

// ----------- timer -----------

uint64_t get_time_us();

// ----------- log -----------

#define ANSI_FG_BLACK   "\33[1;30m"
#define ANSI_FG_RED     "\33[1;31m"
#define ANSI_FG_GREEN   "\33[1;32m"
#define ANSI_FG_YELLOW  "\33[1;33m"
#define ANSI_FG_BLUE    "\33[1;34m"
#define ANSI_FG_MAGENTA "\33[1;35m"
#define ANSI_FG_CYAN    "\33[1;36m"
#define ANSI_FG_WHITE   "\33[1;37m"
#define ANSI_BG_BLACK   "\33[1;40m"
#define ANSI_BG_RED     "\33[1;41m"
#define ANSI_BG_GREEN   "\33[1;42m"
#define ANSI_BG_YELLOW  "\33[1;43m"
#define ANSI_BG_BLUE    "\33[1;44m"
#define ANSI_BG_MAGENTA "\33[1;35m"
#define ANSI_BG_CYAN    "\33[1;46m"
#define ANSI_BG_WHITE   "\33[1;47m"
#define ANSI_NONE       "\33[0m"

#define ANSI_FMT(str, fmt) fmt str ANSI_NONE

#define _Log(...) \
    do { \
        printf(__VA_ARGS__); \
    } while (0)
#define Log(format, ...) \
		_Log(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \
				__FILE__, __LINE__, __func__, ## __VA_ARGS__)

#define Assert(cond, format, ...) \
	do { \
		if (!(cond)) { \
			fflush(stdout); \
            fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ##  __VA_ARGS__); \
			assert(cond); \
            exit(-1); \
		} \
	} while (0)

#define Panic(format, ...) Assert(0, format, ## __VA_ARGS__)

#define TODO() Panic("please implement me")

#include <string>
#include <vector>

inline std::vector<std::string> string_split(const std::string& str, char delim) {
    std::vector<std::string> elems;
    auto lastPos = str.find_first_not_of(delim, 0);
    auto pos = str.find_first_of(delim, lastPos);
    while (pos != std::string::npos || lastPos != std::string::npos) {
        elems.push_back(str.substr(lastPos, pos - lastPos));
        lastPos = str.find_first_not_of(delim, pos);
        pos = str.find_first_of(delim, lastPos);
    }
    return elems;
}

#include <chrono>

inline uint64_t get_time_us() {
    auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch();
    auto us = std::chrono::duration_cast<std::chrono::microseconds>(time_since_epoch).count();
    return us;
}

#endif
